package com.sun.managementsystemsimulationhomeworkcode.chapter2.init;

import com.sun.managementsystemsimulationhomeworkcode.chapter2.arrive.ExponentialGenerator;
import com.sun.managementsystemsimulationhomeworkcode.chapter2.pojo.Group;
import com.sun.managementsystemsimulationhomeworkcode.chapter2.pojo.Job;
import com.sun.managementsystemsimulationhomeworkcode.chapter2.pojo.MyMachine;
import com.sun.managementsystemsimulationhomeworkcode.chapter2.pojo.MySystem;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 工件处理
 *
 * @author Haoran Sun
 * @since 2024/09/18
 */


public class JobProcess {
    /**
     * <p>
     * 工件初始化
     * </p>
     * <p>
     * <p>
     * 首先只能知道工件的到达时间和工件类型，
     * 其他信息需要根据 系统内状态 来计算
     * <p>
     * 因此这里初始化只进行工件的到达时间和工件类型初始化
     * </p>
     */
    public static void initJob(List<Job> result) {
        ArrayList<Double> jobArriveTimeList = ExponentialGenerator.generate();

        List<Job> jobs = jobArriveTimeList.stream().map(
                jobArriveTime -> {
                    Job job = new Job();
                    
                    job.setId(jobArriveTime.hashCode());
                    job.setArriveTime(jobArriveTime);
                    // 随机生成工件类型
                    Random random = new Random();
                    int type = random.nextDouble() < 0.4 ? 1 : 2;
                    job.setType(type);
                    return job;
                }
        ).toList();
        result.addAll(jobs);

    }

    /**
     * 推进模拟时钟
     *
     * @param jobs     工件列表
     * @param mySystem 系统状态
     * @param time     模拟时钟
     * @return result 机器号   机器号为 1、2、3则进行机器的出队操作  为4则进行入队操作
     */
    public static ProcessJobResult processJob(List<Job> jobs, MySystem mySystem, double time) {

        // 1、获取当前系统内所有机器的状态
        // 比较最小的时间
        // （jobs 中的第一个的到达时间；system中所有机器中的离开的最小时间）

        double minTime = 200000;
        if (!jobs.isEmpty()) {
            minTime = Math.min(minTime, jobs.get(0).getArriveTime());
        }
        int machineId = 4;
        for (Group group : mySystem.getGroups()) {
            for (MyMachine machine : group.getMachines()) {
                Job job = machine.getJob();
                if (job != null) {
                    if (job.getEndTime() < minTime) {
                        minTime = job.getEndTime();
                        machineId = machine.getId();
                    }
                }
            }
        }

        time = minTime;

        return ProcessJobResult.builder()
                .machineId(machineId)
                .time(time)
                .type(machineId == 4 ? 1 : 2)
                .build();
    }


    /**
     * A组1类工件的处理时间设置
     */
    public static void a1ProcessTimeSetter(Job job) {
        // 设定加工时间的范围
        // 最小加工时间
        double minProcessingTime = 5;
        // 最大加工时间
        double maxProcessingTime = 14;

        Random random = new Random();
        double processingTime = minProcessingTime + (maxProcessingTime - minProcessingTime) * random.nextDouble();

        job.setProcessTime(processingTime/10);


    }

    /**
     * A组2类工件的处理时间设置
     */
    public static void a2ProcessTimeSetter(Job job) {
        // 最小值（单位：小时）
        double min = 50.0 ;
        // 众数（单位：小时）
        double mode = 60.0;
        // 最大值（单位：小时）
        double max = 80.0 ;

        Random random = new Random();

        // 生成一定数量的加工时间样本
        double triangularRandom = generateTriangular(min, mode, max, random.nextDouble())/60;

        job.setProcessTime(triangularRandom);
    }

    /**
     * B组工件的处理时间设置
     */
    public static void bProcessTimeSetter(Job job) {
        // 最小加工时间
        double minProcessingTime = 3;
        // 最大加工时间
        double maxProcessingTime = 5;
        // 创建随机数生成器实例
        Random random = new Random();
        double processingTime = minProcessingTime + (maxProcessingTime - minProcessingTime) * random.nextDouble();
        job.setProcessTime(processingTime);
    }


    /**
     * 使用三角分布生成随机数。
     *
     * @param min           最小值
     * @param mode          众数
     * @param max           最大值
     * @param uniformRandom 均匀分布的随机数
     * @return 三角分布的随机数
     */
    private static double generateTriangular(double min, double mode, double max, double uniformRandom) {
        double a = min;
        double c = mode;
        double b = max;
        double u = uniformRandom;
        double d = c - a;
        double f = (b - a) - d;

        if (u < d / (b - a)) {
            return a + Math.sqrt(u * (b - a) * d);
        } else {
            return b - Math.sqrt(f * (b - a) - u * f);
        }
    }

}
